
window.requestAnimFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
    window.setTimeout(callback, 1000 / 30);
};

// 游戏数据存储对象
var gameInfo={

    // 页面上所有的元素
    elements:{},

    // 怪兽元素
    monsters:[],

    // 游戏结果，是输还是赢
    gameResult:"",

    // 游戏分数
    score:0,

    // 当前关卡
    currentLevel:1,

    // 所有关卡
    totalLevel:10,

}

// 设置个数属性不可遍历，主要为了给页面元素起一个名字
Object.defineProperty(gameInfo.elements,"len",{
    enumerable:false,
    writable:true,
    value:0
})


// 基础类
class BaseItem {

    constructor({top, left, width, height,speed=10, bg = '#333'}){

        this.width = width;
        this.height = height;
        this.top = top;
        this.left = left;
        this.bg = bg;
        this.speed = speed;

        var elements = gameInfo.elements

        elements.len++

        var ItemName  =this.index = "rect_"+elements.len

        elements[ItemName] =this

    }

    // 画上去
    draw(context){

		context.fillStyle = this.bg;
		context.fillRect(this.left, this.top, this.width, this.height);

    }

    // 移动
    move(direction,num){
        

        num = num || this.speed || 10

		switch (direction) {
			case 'up':
				this.top -= num;
				break;

			case 'down':
				this.top += num;
				break;

			case 'left':
				this.left -= num;
				break;

			case 'right':
				this.left += num;
				break;
		}

    }

    // 移动节点
    remove({left,top,w,h}={}){   

        // 移除画布
		context.clearRect(this.left + left, this.top + top, this.width + w, this.height + h);


        // 删除保存的节点
        delete gameInfo.elements[this.index]
    }

    // 判断是否碰撞
    getIsDetect(item){

		var w = this.width;
		var h = this.height;
		var left = this.left;
		var top = this.top;
		var bottom = top + h;
        var right = left + w;

		// 想要检测的物体
		var d_w = item.width;
		var d_h = item.height;
		var d_left = item.left;
		var d_top = item.top;
		var d_right = d_left + d_w;
		var d_bottom = d_top + d_h;
    
		var R = right < d_left, // 右碰到 左
        L = left > d_right, // 左碰到 右
        T = top > d_bottom, // 头碰到了尾
        B = bottom < d_top; //  尾碰到了头

        if(!R&&!L&&!T&&!B){
            return true
        }

        return false

    }

}


// 飞机类
class Plane extends BaseItem{

    constructor({top, left, width, height, bg,speed=10 }){
        super({top, left, width, height, bg,speed })
    }

    // 发射子弹
    fire(){
        
        var left = this.left;
        var top = this.top;
        var w = this.width;
        var h = this.height;

        var bullet = new Bullet({
            left: left + w / 2 - 2,
            top: top - 20,
            width: 4,
            height: 8,
            bg: 'red'
        });

        // 更新子弹的位置 + 判断是否击中怪兽
        updateCallback.push(function() {
            
            bullet.fly()

            var monsters = gameInfo.monsters
            
            // 判断是否 击中怪兽
            for (var i=0,len = monsters.length;i< len;i++) {

                const monster = monsters[i];

                //  判断是否碰撞
                var isdetect = bullet.getIsDetect(monster);

                if (isdetect) {
                    
                    bullet.remove();
                    monster.eliminate(i)

                    gameInfo.score++

                    return;
                }
                
            }
        })


    }

    // 控制飞机
    control(){

        //  方向键
        document.onkeydown =(e)=> {

            var eCode = e.keyCode;
            var left = this.left;
            var top = this.top;
            var w = this.width;
            var h = this.height;

            // if(gameInfo.isOver) return 

            // left
            if (eCode == 37 && !(left <= 0)) {
                this.move("left");
            } 
            
            // up
            else if (eCode == 38 && !(top <= 0)) {
                
                this.move("up");
            } 
            
            //right
            else if (eCode == 39 && !(left + w >= canvas.width)) {
                
                this.move("right");
            } 
            
            // down
            else if (eCode == 40 && !(top + h >= canvas.height)) {
                
                this.move("down");
            } 

            // 空格 发射
            else if (eCode == 32) {
                
                this.fire();
            }

        };
    }

}


// 子弹类
class Bullet extends BaseItem{
    
    constructor({top, left, width, height, bg,speed=5 }){

        super({top, left, width, height, bg ,speed})

    }

    // 子弹飞行
    fly(){

        // 如果 子弹飞出屏幕，就停止
        if (this.top < -2 * this.height || this.left < -2 * this.width) {
            this.remove({ });
            return;
        }

		this.move('up');

    }

}


// 怪兽类
class Monster extends BaseItem{
    
    constructor({top, left, width, height, bg ,speed=0.5,yspeed}){

        super({top, left, width, height, bg,speed })

        this.yspeed = yspeed

        gameInfo.monsters.push(this)
    }

    // 消除怪兽
    eliminate(i){

        gameInfo.monsters.splice(i,1)
        this.remove();

    }

}

// 怪兽移动的方向
Monster.prototype.direction="right"


// 创建文字
class createText{

    constructor({top,left,text,fontStyle,color}){

        this.top =top
        this.left = left
        this.text=text
        this.fontStyle=fontStyle
        this.color=color
        
    }

    draw(context){

        context.font = this.fontStyle;
        context.fillStyle = this.color
		context.fillText(this.text,this.left, this.top,);

    }

}


// 逐帧更新画布
function updateCanvas(params) {
    
    // 擦除画布函数，可以将整个画布擦除
    context.clearRect(0, 0, canvas.width, canvas.height);

    var result = gameInfo.gameResult;
    var isWin = result =="win"
    var isLose = result=="lose"

    // 游戏输赢
    if(isWin ||isLose) {

        winText.text="你赢了，分数是 "+gameInfo.score

        isLose && loseText.draw(context)
        isWin && winText.draw(context)

        return
    } 
    
    // 各种更新函数 = 判断是否碰边 + 位置更新
    for (var i = 0, len = updateCallback.length; i < len; i++) {
    
        var item = updateCallback[i]

        item()
    
    }

    var elements = gameInfo.elements
    
    // 绘制所有元素
    for (var i in elements) {

        var item = elements[i]
		item.draw(context);
    
    }

    requestAnimationFrame(updateCanvas)

}

// ### 控制整个画布渲染和擦除 ###
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var updateCallback=[] 

// 创建一个飞机
var plane = new Plane({
    left: 50,
	top: 400,
	width: 80,
    height: 80,
    bg:"red"
})

plane.control()

// 创建 5个 怪兽
for (let index = 0; index < 5; index++) {

    const monster = new Monster({
        left: 50+70*index,
        top: 50,
        width: 50,
        height: 50,
        bg: 'black',
        yspeed:20
    });
    
}

// 更新怪兽位置
updateCallback.push(function(){

    var monsters = gameInfo.monsters

    // 已经没有怪兽了
    if(monsters.length==0) {
        
        gameInfo.gameResult="win"
        return

    } 
    
    var isDown=false

    var a_monster =  monsters[0]

    var isOnLeft = a_monster.left<=0
    var isOnRight = monsters[monsters.length-1].left>= canvas.width-50
    var yspeed = a_monster.yspeed
    
    // 判断是否碰到画布边缘，碰到就换方向运行
    if(isOnLeft ||isOnRight) {

        isOnLeft && (a_monster.direction="right")
        isOnRight && (a_monster.direction="left")
        isDown=true
    }
    
    var direction = a_monster.direction

    // 判断怪兽是否击中 飞机
    for (var i=0,len = monsters.length;i<len ;i++) {
        
        var monster = monsters[i]

        if(monster.getIsDetect(plane)){
            
            gameInfo.gameResult="lose"

            return  
        }
        
        monster.move(direction)
        isDown && monster.move("down",yspeed)

    }
    

})

// 显示赢了
var winText =new createText({
    top:200,
    left:50,
    text:"你赢了",
    fontStyle:"50px  arial",
    color:"#000"
})

// 显示输了
var loseText =new createText({
    top:200,
    left:50,
    text:"哈哈，你输了啊.....",
    fontStyle:"50px  arial",
    color:"#000"
})

updateCanvas()

